
#include <linux/module.h>

/**
 * files:
 * include/linux/moduleparam.h
 * kernel/params.c
 *
 * macros:
 * module_param
 * module_param_unsafe        // taints kernel
 * module_param_named
 * module_param_named_unsafe
 *
 * module_param_array
 * module_param_array_named
 *
 * module_param_hw
 * module_param_hw_named
 * module_param_hw_array
 *
 * module_param_string
 */

/**
 * module_param - typesafe helper for a module/cmdline parameter
 * @name: the variable to alter, and exposed parameter name.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * @name becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 * ".") the kernel commandline parameter.  Note that - is changed to _, so
 * the user can use "foo-bar=1" even for variable "foo_bar".
 *
 * @perm is 0 if the variable is not to appear in sysfs, or 0444
 * for world-readable, 0644 for root-writable, etc.  Note that if it
 * is writable, you may need to use kernel_param_lock() around
 * accesses (esp. charp, which can be kfreed when it changes).
 *
 * The @type is simply pasted to refer to a param_ops_##type and a
 * param_check_##type: for convenience many standard types are provided but
 * you can create your own by defining those variables.
 *
 * Standard types are:
 *	byte, hexint, short, ushort, int, uint, long, ulong
 *	charp: a character pointer
 *	bool: a bool, values 0/1, y/n, Y/N.
 *	invbool: the above, only sense-reversed (N = true).
 */

#define __dec_param(ctype, stype, val) \
    static ctype param_##stype = val; \
    module_param(param_##stype, stype, S_IRUGO | S_IWUSR); \
    MODULE_PARM_DESC(param_##stype, "[param: " #ctype "]");

__dec_param(unsigned char,  byte,   10);
__dec_param(short,          short,  10);
__dec_param(unsigned short, ushort, 10);
__dec_param(int,            int,    10);
__dec_param(unsigned int,   uint,   10);
__dec_param(long,           long,   10);
__dec_param(unsigned long,  ulong,  10);
__dec_param(unsigned long long, ullong, 10);
__dec_param(unsigned int,   hexint, 0xFF00);

__dec_param(char *,         charp,  "charp param");

__dec_param(bool,           bool,   1);
__dec_param(bool,           invbool, 1);


/**
 * module_param_named - typesafe helper for a renamed module/cmdline parameter
 * @name: a valid C identifier which is the parameter name.
 * @value: the actual lvalue to alter.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * Usually it's a good idea to have variable names and user-exposed names the
 * same, but that's harder if the variable must be non-static or is inside a
 * structure.  This allows exposure under a different name.
 */

#define __dec_param_named(ctype, stype, val) \
    static ctype var_##stype = val; \
    module_param_named(param_named_##stype, var_##stype, stype, S_IRUGO | S_IWUSR); \
    MODULE_PARM_DESC(param_named_##stype, "[param named: " #ctype "]");

__dec_param_named(unsigned char,  byte,   10);  
__dec_param_named(short,          short,  10);
__dec_param_named(unsigned short, ushort, 10);
__dec_param_named(int,            int,    10);
__dec_param_named(unsigned int,   uint,   10);
__dec_param_named(long,           long,   10);
__dec_param_named(unsigned long,  ulong,  10);
__dec_param_named(unsigned long long, ullong, 10);
__dec_param_named(unsigned int,   hexint, 0xFF00);

__dec_param_named(char *,         charp,  "charp param");

__dec_param_named(bool,           bool,   1);
__dec_param_named(bool,           invbool, 1);


/**
 * module_param_array - a parameter which is an array of some type
 * @name: the name of the array variable
 * @type: the type, as per module_param()
 * @nump: optional pointer filled in with the number written
 * @perm: visibility in sysfs
 *
 * Input and output are as comma-separated values.  Commas inside values
 * don't work properly (eg. an array of charp).
 *
 * ARRAY_SIZE(@name) is used to determine the number of elements in the
 * array, so the definition must be visible.
 */

#define __dec_param_array(ctype, stype, vals...) \
    static ctype param_array_##stype[8] = {vals}; \
    module_param_array(param_array_##stype, stype, NULL, S_IRUGO | S_IWUSR); \
    MODULE_PARM_DESC(param_array_##stype, "[param array: " #ctype "]");

__dec_param_array(int,    int,   1, 2, 3, 4);
__dec_param_array(char *, charp, "one", "two", "three", "four");


/**
 * module_param_array_named - renamed parameter which is an array of some type
 * @name: a valid C identifier which is the parameter name
 * @array: the name of the array variable
 * @type: the type, as per module_param()
 * @nump: optional pointer filled in with the number written
 * @perm: visibility in sysfs
 *
 * This exposes a different name than the actual variable name.  See
 * module_param_named() for why this might be necessary.
 */

#define __dec_param_array_named(ctype, stype, vals...) \
    static ctype var_array_##stype[8] = {vals}; \
    module_param_array_named(param_array_named_##stype, var_array_##stype, stype, NULL, S_IRUGO | S_IWUSR); \
    MODULE_PARM_DESC(param_array_named_##stype, "[param array named: " #ctype "]");

__dec_param_array_named(int,    int,   1, 2, 3, 4);
__dec_param_array_named(char *, charp, "one", "two", "three", "four");

/**
 * module_param_string - a char array parameter
 * @name: the name of the parameter
 * @string: the string variable
 * @len: the maximum length of the string, incl. terminator
 * @perm: visibility in sysfs.
 *
 * This actually copies the string when it's set (unlike type charp).
 * @len is usually just sizeof(string).
 */
#define PARAM_STRING_LEN
static char var_param_string[PARAM_STRING_LEN] = "string param";
module_param_string(param_string, var_param_string, sizeof(var_param_string), S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(param_string, "[string param]");

static int __init param_init(void)
{
	pr_info("%s enter\n", __func__);
	printk(KERN_NOTICE "see parameters in /sys/module/%s/parameters\n", KBUILD_MODNAME);
	return 0;
}

static void __exit param_exit(void)
{
	pr_info("%s exit\n", __func__);
}

module_init(param_init);
module_exit(param_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kingdix10");
